On each subsequent deployment from Visual
Studio.NET, the generated receive port will have any out-of-band
changes overwritten by the deployment action.
Chaining
orchestration together is a tricky endeavor and one that can leave you
in a messy state if you are too quick with a design decision. By
"chaining orchestrations", I mean exploiting multiple orchestrations to
implement a business process. There are a few options at your disposal
listed here and ordered from most coupled to least coupled.
Call Orchestration or Start Orchestration shape: An orchestration uses these shapes in order to kick off an additional workflow process. The Call Orchestration is used for synchronous connection with the new orchestration while the Start Orchestration
is a fire-and-forget action. This is a useful tactic for sharing state
data (for example variables, messages, ports) from the source
orchestration to the target. However, both options require a tight
coupling of the source orchestration to the target. Version changes to
the target orchestration would likely require a redeployment of the
source orchestration.
Partner direct bound ports: These provide you the capability to communicate between orchestrations using ports. In the forward partner direct binding
scenario, the sender has a strong coupling to the receiver, while the
receiver knows nothing about the sender. This works well in situations
where there are numerous senders and only one receiver. Inverse partner direct binding
means that there is a tight coupling between the receiver and the
sender. The sender doesn't know who will receive the command, so this
scenario is intended for cases where there are many receivers for a
single sender. In both cases, you have tight coupling on one end, with
loose-coupling on the other.
MessageBox direct binding:
This is the most loosely-coupled way to share data between
orchestrations. When you send a message out of an orchestration through
a port marked for MessageBox direct binding, you are simply placing a
message onto the bus for anyone to consume. The source orchestration
has no idea where the data is going, and the recipients have no idea
where it's been.
MessageBox
direct binding provides a very loosely-coupled way to send messages
between different orchestrations and endpoints. In Chapter 7, I'll show
you how to use the BizTalk Business Rules Engine alongside
orchestrations to seamlessly link, add, and replace orchestrations in a
complex business process.
Critical point
While MessageBox direct binding is great, you do lose the ability to send the additional state data that a Call Orchestration
shape will provide you. So, as with all architectural decisions, you
need to decide if the sacrifice (loose coupling, higher latency) is
worth the additional capabilities.
Decisions
can be made during BizTalk messaging configuration that promote a
loosely-coupled BizTalk landscape. For example, both receive ports and
send ports allow for the application of maps to messages flying past.
In each case, multiple maps can be added. This does NOT mean that all
the maps will be applied to the message, but rather, it allows for
sending multiple different message types in, and emitting a single type
(or even multiple types) out the other side. By applying transformation
at the earliest and latest moments of bus processing, you loosely
couple external formats and systems from internal canonical formats. We
should simply assume that all upstream and downstream systems will
change over time, and configure our application accordingly.
Another
means for loosely coupling BizTalk solutions involves the exploitation
of the publish-subscribe architecture that makes up the BizTalk message
bus. Instead of building solely point-to-point solutions and figuring
that a SOAP interface makes you service oriented, you should also
consider loosely coupling the relationship between the service input
and where the data actually ends up. We can craft a series of routing
decision that take into account message content or context and direct
the message to one or more relevant processes/endpoints. While
point-to-point solutions may be appropriate for many cases, don't
neglect a more distributed pattern where the data publisher does not
need to explicitly know exactly how their data will be processed and
routed by the message bus.
When
identifying subscriptions for our send ports, we should avoid tight
coupling to metadata attributes that might limit the reuse of the port.
For instance, you should try to create subscriptions on either the
message type or message content instead of context attributes such as
the inbound receive port name. Ports should be tightly coupled to the
MessageBox and messages it stores, not to attributes of its publisher.
That said, there are clearly cases where a subscriber is specifically
looking for data that corresponds to a targeted piece of metadata such
as the subject line of the email received by BizTalk. As always, design
your solution in a way that solves your business problem in an
efficient manner.
Abstraction
The
SOA concept of abstraction is all about making your service a black box
to consumers. All that the consumers see is an interface while
possessing no visibility into the soft meaty center of the service. The
underlying service could be very simple or mind-numbingly complex. It
could have a very stable core, or be undergoing consistent upgrades.
The service logic could integrate with a single backend system, or
choreograph communication across ten applications. None of these things
should matter to a service consumer who has an interface that provides
an abstract perspective of the service itself.
This
is where the art of service contract design plays an immense role. The
contract needs to strike the right balance of information hiding, while
still demanding information material to an effective service. Consider
operation granularity. I have an application that requires a series of
API calls in order to insert a new order for a product. First I need to
check the available stock, then decrement the stock, and then add the
new order to the system. If I were a brand new SOA developer, I might
take that API, slap a SOAP interface on it, and declare our application
to be service-oriented. Wrong answer! We don't always need to expose
that level of granularity to the consumer. Let's bestow upon them a
nice coarse-grained interface that hides the underlying system API
messiness and simply accepts the product order through a SubmitOrder operation.
Completely non-technical abstraction example
When
my order is taken at a restaurant, I don't have the opportunity (or
desire!) to outline the sequence of steps I wish the chef to take in
preparing my meal. Instead, I am asked a simple series of questions
that are recorded and forwarded on to the kitchen. Inside the kitchen,
a swift, complex set of actions are taken to get the food ready all at
once. From my perspective while seated at the table, I simply made a
single request and will get back what I expect. If the chef decides to
try prepare a meal in a brand new way, that's of no consequence to me
(unless it tastes bad). The underlying service may undergo mild or
fundamental changes, but the ordering interface provided to me will
remain fairly static.
Why
does abstraction matter? A well-defined interface that successfully
hides the service logic provides a way to change implementation details
over time, while still respecting the original contract. Just because a
service undergoes plumbing modifications doesn't mean that service
consumers must take note of those changes or behave any differently. As
long as the interface remains consistent, the service itself can
accommodate either simple or radical changes. A nicely abstracted
interface promotes loose coupling between the service sender and
receiver while a contract that too deeply reveals implementation
details can lead to tight coupling.